/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tonyodev.fetchapp.ability;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.agp.utils.Color;
import ohos.agp.window.dialog.ToastDialog;
import ohos.bundle.IBundleManager;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;

import com.chinasoft_ohos.commontools.Toast.Toast;
import com.muddzdev.styleabletoast.styleabletoast.Constants;
import com.tonyodev.fetch2.AbstractFetchListener;
import com.tonyodev.fetch2.Download;
import com.tonyodev.fetch2.Error;
import com.tonyodev.fetch2.Fetch;
import com.tonyodev.fetch2.FetchConfiguration;
import com.tonyodev.fetch2.FetchFileServerDownloader;
import com.tonyodev.fetch2.FetchListener;
import com.tonyodev.fetch2.Priority;
import com.tonyodev.fetch2.Request;
import com.tonyodev.fetch2core.Downloader;
import com.tonyodev.fetch2core.FetchCoreUtils;
import com.tonyodev.fetch2core.FetchFileServerUriBuilder;
import com.tonyodev.fetch2core.FileResource;
import com.tonyodev.fetch2core.MutableExtras;
import com.tonyodev.fetch2fileserver.FetchFileServer;
import com.tonyodev.fetchapp.Data;
import com.tonyodev.fetchapp.ResourceTable;
import com.tonyodev.fetchapp.Utils;

import org.jetbrains.annotations.NotNull;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import timber.log.Timber;

import static ohos.security.SystemPermission.WRITE_USER_STORAGE;

/**
 * @since 2021-05-20
 */
public class FileServerAbility extends Ability {

    private static final int STORAGE_PERMISSION_CODE = 100;
    public static final String FETCH_NAMESPACE = "fileServerActivity";
    public static final String CONTENT_PATH = "test_file.db";
    private Text textView;
    private FetchFileServer fetchFileServer;

    private Fetch fetch;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        getWindow().setStatusBarColor(Color.getIntColor("#303f9f"));
        super.setUIContent(ResourceTable.Layout_ability_file_server);

        initView();
    }

    private void initView() {
        textView = (Text) findComponentById(ResourceTable.Id_textView);
        final FetchConfiguration fetchConfiguration = new FetchConfiguration.Builder(this)
            .setFileServerDownloader(new FetchFileServerDownloader(Downloader.FileDownloaderType.PARALLEL, 20_000))
            .setNamespace(FETCH_NAMESPACE)
            .build();
        fetch = Fetch.Impl.getInstance(fetchConfiguration);
        try {
            fetchFileServer = new FetchFileServer.Builder(this)
                .setAuthenticator((sessionId, authorization, fileRequest) -> authorization.equals("password"))
                .build();
        } catch (IOException e) {
            e.printStackTrace();
        }

        fetchFileServer.start();
        checkStoragePermission();
    }


    @Override
    protected void onActive() {
        super.onActive();
        fetch.addListener(fetchListener);
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        fetch.removeListener(fetchListener);
    }

    @Override
    protected void onStop() {
        super.onStop();
        fetch.close();
        fetchFileServer.shutDown(false);
    }

    private void checkStoragePermission() {
        // 权限申请
        List<String> permissionsToRequest = new ArrayList<>();
        String[] permissions = new String[]{WRITE_USER_STORAGE};
        for (String permission : permissions) {
            if (verifyCallingPermission(permission) != IBundleManager.PERMISSION_GRANTED) {
                // 应用未被授予权限
                if (canRequestPermission(permission)) { // 是否可以申请弹框授权 如果可以就把权限添加到列表中
                    permissionsToRequest.add(permission);
                }
            }
        }

        if (!permissionsToRequest.isEmpty()) { //
            requestPermissionsFromUser(permissions, STORAGE_PERMISSION_CODE); // 说明有权限没有申请
        } else {
            copyRawFileToFilesDir();
        }
    }

    @Override
    public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults);
        if (requestCode == STORAGE_PERMISSION_CODE) {
            copyRawFileToFilesDir();
        } else {
            Toast.show(getString(ResourceTable.String_permission_not_enabled));
        }
    }

    private void copyRawFileToFilesDir() {
        new Thread(() -> {
                final String testFilePath = Data.getSaveDir(this) + "/source/" + CONTENT_PATH;
                final File file = Utils.createFile(testFilePath);
                ResourceManager resourceManager = getResourceManager();
                RawFileEntry rawFileEntry = resourceManager.getRawFileEntry("resources/rawfile/test_file.db");
                try {
                    InputStream inputStream = new BufferedInputStream(rawFileEntry.openRawFile());
                    OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file));
                    byte[] buffer = new byte[1024];
                    int read;
                    long readBytes = 0;
                    while (((read = inputStream.read(buffer, 0, 1024)) != -1)) {
                        readBytes += read;
                        outputStream.write(buffer, 0, read);
                    }
                    inputStream.close();
                    outputStream.flush();
                    outputStream.close();
                    addFileResourceToServer(file, readBytes);
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }).start();
    }

    private void addFileResourceToServer(File file, long fileLength) throws IOException {
        final FileResource fileResource = new FileResource();
        fileResource.setFile(file.getCanonicalPath());
        fileResource.setName(file.getName());
        fileResource.setId(file.getCanonicalPath().hashCode());
        fileResource.setLength(fileLength);
        final String fileMd5 = FetchCoreUtils.getFileMd5String(file.getCanonicalPath());
        if (fileMd5 != null) {
            fileResource.setMd5(fileMd5);
        }
        final MutableExtras extras = new MutableExtras();
        extras.putLong("contentLength", fileLength);
        extras.putString("contentName", file.getName());
        extras.putString("contentSampleKey", "contentSampleText");
        fileResource.setExtras(extras.toExtras());
        fetchFileServer.addFileResource(fileResource);
        downloadFileResourceUsingFetch();
        fetch.getFetchFileServerCatalog(getCatalogRequest(),
            result -> {
                if (result != null){
                    Timber.d("Catalog:" + result.toString());
                }
            },
            error -> Timber.d("Catalog Fetch error:" + error.toString()));
    }


    private Request getCatalogRequest() {
        final String url = new FetchFileServerUriBuilder()
            .setHostInetAddress(fetchFileServer.getAddress(), fetchFileServer.getPort())
            .setFileResourceIdentifier("Catalog.json")
            .toString();
        final Request request = new Request(url, getFile("(1)"));
        final MutableExtras extras = new MutableExtras();
        extras.putString("sampleKey", "sampleTextDataInExtras");
        request.setExtras(extras.toExtras());
        request.addHeader("Authorization", "password");
        request.setPriority(Priority.HIGH);
        return request;
    }

    private void downloadFileResourceUsingFetch() {
        fetch.addListener(fetchListener).enqueue(getRequest(), request -> {
            Timber.d(request.toString());
        }, error -> {
            Timber.d(error.toString());
        });
    }

    private Request getRequest() {
        final String url = new FetchFileServerUriBuilder()
            .setHostInetAddress(fetchFileServer.getAddress(), fetchFileServer.getPort())
            .setFileResourceIdentifier(CONTENT_PATH)
            .toString();
        final Request request = new Request(url, getFile("(1)"));
        request.addHeader("Authorization", "password");
        request.setPriority(Priority.HIGH);
        return request;
    }

    private FetchListener fetchListener = new AbstractFetchListener() {

        @Override
        public void onCompleted(Download download) {
            super.onCompleted(download);
            final String completed = "Completed Download";
            textView.setText(completed);
            Timber.d("Download From FileServer completed");
        }

        @Override
        public void onQueued(Download download, boolean waitingOnNetwork) {
        }

        @Override
        public void onProgress(Download download, long etaInMilliSeconds, long downloadedBytesPerSecond) {
            final String progress = "Progress: " + download.getProgress() + "%";
            if(download.getProgress()==99){
                textView.setText("Completed Download");
            }else{
                textView.setText(progress);
                Timber.d("Download From FileServer Progress: " + download.getProgress() + "%");
            }
        }

        @Override
        public void onError(Download download, Error error, Throwable throwable) {
            super.onError(download, error, throwable);
            final String err = "Download From FileServer Error " + download.getError().toString();
            textView.setText(err);
            Timber.d(err);
        }
    };

    private String getFile(final String incrementer) {
        return Data.getSaveDir(this) + "/data/test_file" + incrementer + ".db";
    }
}
